package day28.ThreadTest;

/**
 * 线程同步和线程通信测试类
 * 演示Java中线程同步和通信的基本概念
 * 演示了如何在多线程环境中安全地共享数据
 * 展示了使用synchronized关键字和wait/notify机制
 * 
 * 涉及知识点：
 * 1. 多线程基础概念
 * 2. 线程同步机制
 * 3. 线程间通信
 * 4. 生产者-消费者模式
 */
public class SynchronizationTest {
    public static void main(String[] args) {
        // 创建共享资源对象
        SharedResource resource = new SharedResource();
        
        // 创建生产者线程
        Thread producer = new Thread(new Producer(resource), "Producer");
        // 创建消费者线程
        Thread consumer = new Thread(new Consumer(resource), "Consumer");
        
        // 启动线程
        producer.start();
        consumer.start();
    }
}

/**
 * 共享资源类，用于演示线程同步
 * 
 * 涉及知识点：
 * 1. synchronized关键字 - 用于方法级别的同步
 * 2. Object类的wait()和notifyAll()方法 - 实现线程间通信
 * 3. 线程状态控制 - wait()使线程进入等待状态，notifyAll()唤醒等待线程
 * 4. 原子性操作 - 通过同步确保数据一致性
 */
class SharedResource {
    private int data;
    private boolean available = false; // 标记数据是否可用
    
    /**
     * 生产数据的方法，使用synchronized确保线程安全
     * @param value 要生产的值
     * 
     * 涉及知识点：
     * 1. synchronized方法 - 保证同一时刻只有一个线程可以执行该方法
     * 2. wait()方法 - 释放对象锁并使当前线程进入等待状态
     * 3. notifyAll()方法 - 唤醒在该对象上等待的所有线程
     * 4. 线程调度 - 通过wait/notify机制控制线程执行顺序
     */
    public synchronized void produce(int value) {
        // 如果数据已经可用，则等待消费者消费
        // 使用while循环而不是if是为了防止虚假唤醒问题
        while (available) {
            try {
                wait(); // 释放锁并等待，线程进入阻塞状态
            } catch (InterruptedException e) {
                // 涉及知识点：InterruptedException处理
                // 当线程在wait状态时被interrupt()方法中断会抛出此异常
                Thread.currentThread().interrupt(); // 恢复中断状态
            }
        }
        
        // 生产数据
        this.data = value;
        this.available = true;
        System.out.println(Thread.currentThread().getName() + " produced: " + value);
        
        // 通知等待的消费者线程
        // 涉及知识点：notifyAll() vs notify() 
        // notifyAll()唤醒所有等待线程，notify()只唤醒一个等待线程
        notifyAll();
    }
    
    /**
     * 消费数据的方法，使用synchronized确保线程安全
     * @return 消费的数据
     * 
     * 涉及知识点：
     * 1. synchronized方法 - 保证线程安全访问共享资源
     * 2. wait()/notify()机制 - 实现生产者和消费者之间的协调
     * 3. 返回值处理 - 线程安全地返回共享数据
     */
    public synchronized int consume() {
        // 如果没有可用数据，则等待生产者生产
        // 使用while循环检查条件以防止虚假唤醒
        while (!available) {
            try {
                wait(); // 释放锁并等待生产者生产数据
            } catch (InterruptedException e) {
                // 涉及知识点：中断处理机制
                Thread.currentThread().interrupt(); // 恢复线程的中断状态
            }
        }
        
        // 消费数据
        available = false;
        System.out.println(Thread.currentThread().getName() + " consumed: " + data);
        
        // 通知等待的生产者线程
        notifyAll();
        return data;
    }
}

/**
 * 生产者任务类
 * 实现Runnable接口创建线程任务
 * 
 * 涉及知识点：
 * 1. Runnable接口 - 实现多线程的方式之一
 * 2. Thread.sleep() - 线程休眠，不释放锁
 * 3. 线程命名 - 通过构造函数为线程指定名称
 */
class Producer implements Runnable {
    private SharedResource resource;
    
    public Producer(SharedResource resource) {
        this.resource = resource;
    }
    
    @Override
    public void run() {
        // 生产10个数据
        for (int i = 1; i <= 10; i++) {
            resource.produce(i);
            
            // 添加一些延迟，使线程交替执行更明显
            try {
                // 涉及知识点：Thread.sleep()方法
                // 使当前线程休眠指定时间，但不释放已持有的锁
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // 涉及知识点：中断异常处理
                Thread.currentThread().interrupt();
            }
        }
    }
}

/**
 * 消费者任务类
 * 实现Runnable接口创建线程任务
 * 
 * 涉及知识点：
 * 1. Runnable接口 - 创建线程任务的标准方式
 * 2. 异常处理 - 正确处理InterruptedException
 * 3. 线程执行控制 - 通过sleep控制执行节奏
 */
class Consumer implements Runnable {
    private SharedResource resource;
    
    public Consumer(SharedResource resource) {
        this.resource = resource;
    }
    
    @Override
    public void run() {
        // 消费10个数据
        for (int i = 1; i <= 10; i++) {
            resource.consume();
            
            // 添加一些延迟，使线程交替执行更明显
            try {
                // 涉及知识点：线程休眠
                // 通过控制执行节奏更好地观察线程交替执行效果
                Thread.sleep(150);
            } catch (InterruptedException e) {
                // 涉及知识点：线程中断处理最佳实践
                Thread.currentThread().interrupt();
            }
        }
    }
}